home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / UNIX / C / INDENT / IO.C < prev    next >
C/C++ Source or Header  |  1989-09-11  |  19KB  |  733 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)io.c    5.10 (Berkeley) 9/15/88";
  23. #endif /* not lint */
  24.  
  25. #include "indent_globs.h"
  26. #include <ctype.h>
  27. /* POSIX says that fcntl.h should exist.  Linking either sys/fcntl.h
  28.    or sys/file.h to fcntl.h should work fine if you don't have fcntl.h */
  29. #include <fcntl.h>
  30.  
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33.  
  34. int suppress_blanklines = 0;
  35. int         comment_open;
  36.  
  37. int paren_target;
  38.  
  39. /* true if INDENT OFF is in effect */
  40. static int inhibit_formatting;
  41.  
  42. dump_line()
  43. {                /* dump_line is the routine that actually
  44.                  * effects the printing of the new source. It
  45.                  * prints the label section, followed by the
  46.                  * code section with the appropriate nesting
  47.                  * level, followed by any comments */
  48.     register int cur_col,
  49.                 target_col;
  50.     static      not_first_line;
  51.  
  52.     if (parser_state_tos->procname[0]) {
  53.     if (troff) {
  54.         if (comment_open) {
  55.         comment_open = 0;
  56.         fprintf(output, ".*/\n");
  57.         }
  58.         fprintf(output, ".Pr \"%.*s\"\n", parser_state_tos->procname_end - parser_state_tos->procname,
  59.             parser_state_tos->procname);
  60.     }
  61.     parser_state_tos->ind_level = 0;
  62.     parser_state_tos->procname = "\0";
  63.     }
  64.     if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
  65.       /* If we have a formfeed on a blank line, we should just output it,
  66.      rather than treat it as a normal blank line.  */
  67.       if (parser_state_tos->use_ff)
  68.     {
  69.       putc('\014',output);
  70.       parser_state_tos->use_ff = false;
  71.     }
  72.       else
  73.     {
  74.       if (suppress_blanklines > 0)
  75.         suppress_blanklines--;
  76.       else {
  77.         parser_state_tos->bl_line = true;
  78.         n_real_blanklines++;
  79.       }
  80.     }
  81.     }
  82.     else if (!inhibit_formatting) {
  83.     suppress_blanklines = 0;
  84.     parser_state_tos->bl_line = false;
  85.     if (prefix_blankline_requested && not_first_line)
  86.         if (swallow_optional_blanklines) {
  87.         if (n_real_blanklines == 1)
  88.             n_real_blanklines = 0;
  89.         }
  90.         else {
  91.         if (n_real_blanklines == 0)
  92.             n_real_blanklines = 1;
  93.         }
  94.     while (--n_real_blanklines >= 0)
  95.         putc('\n', output);
  96.     n_real_blanklines = 0;
  97.     if (parser_state_tos->ind_level == 0)
  98.         parser_state_tos->ind_stmt = 0;    /* this is a class A kludge. dont do
  99.                  * additional statement indentation if we are
  100.                  * at bracket level 0 */
  101.  
  102.     if (e_lab != s_lab || e_code != s_code)
  103.         ++code_lines;    /* keep count of lines with code */
  104.  
  105.  
  106.     if (e_lab != s_lab) {    /* print lab, if any */
  107.         if (comment_open) {
  108.         comment_open = 0;
  109.         fprintf(output, ".*/\n");
  110.         }
  111.         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  112.         e_lab--;
  113.         cur_col = pad_output(1, compute_label_target());
  114.         if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
  115.                     || strncmp(s_lab, "#endif", 6) == 0)) {
  116.             /* Treat #else and #endif as a special case because any
  117.            text after #else or #endif should be converted to
  118.            a comment.  */
  119.         register char *s = s_lab;
  120.         if (e_lab[-1] == '\n') e_lab--;
  121.         do putc(*s++, output);
  122.         while (s < e_lab && 'a' <= *s && *s<='z');
  123.         while ((*s == ' ' || *s == '\t') && s < e_lab)
  124.             s++;
  125.         if (s < e_lab)
  126.             fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
  127.                 e_lab - s, s);
  128.         }
  129.         else fprintf(output, "%.*s", e_lab - s_lab, s_lab);
  130.         cur_col = count_spaces(cur_col, s_lab);
  131.     }
  132.     else
  133.         cur_col = 1;    /* there is no label section */
  134.  
  135.     parser_state_tos->pcase = false;
  136.  
  137.     if (s_code != e_code) {    /* print code section, if any */
  138.         register char *p;
  139.  
  140.         if (comment_open) {
  141.         comment_open = 0;
  142.         fprintf(output, ".*/\n");
  143.         }
  144.         target_col = compute_code_target();
  145.         /* If a line ends in an lparen character, the following 
  146.            line should not line up with the parenthesis, but
  147.            should be indented by the usual amount.  */
  148.         if (parser_state_tos->last_token == lparen)
  149.           {
  150.         parser_state_tos->paren_indents[parser_state_tos->p_l_follow-1]
  151.           += ind_size - 1;
  152.           }
  153.         {
  154.         register    i;
  155.  
  156.         for (i = 0; i < parser_state_tos->p_l_follow; i++)
  157.             if (parser_state_tos->paren_indents[i] >= 0)
  158.             parser_state_tos->paren_indents[i] = -(parser_state_tos->paren_indents[i] + target_col);
  159.         }
  160.         cur_col = pad_output(cur_col, target_col);
  161.         for (p = s_code; p < e_code; p++)
  162.         if (*p == (char) 0200)
  163.             fprintf(output, "%d", target_col * 7);
  164.         else
  165.             putc(*p, output);
  166.         cur_col = count_spaces(cur_col, s_code);
  167.     }
  168.     if (s_com != e_com)
  169.       {
  170.         if (troff) {
  171.         int         all_here = 0;
  172.         register char *p;
  173.  
  174.         if (e_com[-1] == '/' && e_com[-2] == '*')
  175.             e_com -= 2, all_here++;
  176.         while (e_com > s_com && e_com[-1] == ' ')
  177.             e_com--;
  178.         *e_com = 0;
  179.         p = s_com;
  180.         while (*p == ' ')
  181.             p++;
  182.         if (p[0] == '/' && p[1] == '*')
  183.             p += 2, all_here++;
  184.         else if (p[0] == '*')
  185.             p += p[1] == '/' ? 2 : 1;
  186.         while (*p == ' ')
  187.             p++;
  188.         if (*p == 0)
  189.             goto inhibit_newline;
  190.         if (comment_open < 2 && parser_state_tos->box_com) {
  191.             comment_open = 0;
  192.             fprintf(output, ".*/\n");
  193.         }
  194.         if (comment_open == 0) {
  195.             if ('a' <= *p && *p <= 'z')
  196.             *p = *p + 'A' - 'a';
  197.             if (e_com - p < 50 && all_here == 2) {
  198.             register char *follow = p;
  199.             fprintf(output, "\n.nr C! \\w\1");
  200.             while (follow < e_com) {
  201.                 switch (*follow) {
  202.                 case '\n':
  203.                 putc(' ', output);
  204.                 case 1:
  205.                 break;
  206.                 case '\\':
  207.                 putc('\\', output);
  208.                 default:
  209.                 putc(*follow, output);
  210.                 }
  211.                 follow++;
  212.             }
  213.             putc(1, output);
  214.             }
  215.             fprintf(output, "\n./* %dp %d %dp\n",
  216.                 parser_state_tos->com_col * 7,
  217.                 (s_code != e_code || s_lab != e_lab) - parser_state_tos->box_com,
  218.                 target_col * 7);
  219.         }
  220.         comment_open = 1 + parser_state_tos->box_com;
  221.         while (*p) {
  222.             if (*p == BACKSLASH)
  223.             putc(BACKSLASH, output);
  224.             putc(*p++, output);
  225.         }
  226.         }
  227.         else {        /* print comment, if any */
  228.         register    target = parser_state_tos->com_col;
  229.         register char *com_st = s_com;
  230.  
  231.         target += parser_state_tos->comment_delta;
  232.         while (*com_st == '\t')
  233.             com_st++, target += 8;    /* ? */
  234.         while (target <= 0)
  235.             if (*com_st == ' ')
  236.             target++, com_st++;
  237.             else if (*com_st == '\t')
  238.             target = ((target - 1) & ~7) + 9, com_st++;
  239.             else
  240.             target = 1;
  241.         if (cur_col > target) {    /* if comment cant fit on this line,
  242.                      * put it on next line */
  243.             putc('\n', output);
  244.             cur_col = 1;
  245.             ++parser_state_tos->out_lines;
  246.         }
  247.         while (e_com > com_st && isspace(e_com[-1]))
  248.             e_com--;
  249.         cur_col = pad_output(cur_col, target);
  250.         if (!parser_state_tos->box_com) {
  251.             if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1))
  252.             if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
  253.                 com_st[1] = '*';
  254.             else
  255.                 fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
  256.         }
  257.         fwrite(com_st, e_com - com_st, 1, output);
  258.         parser_state_tos->comment_delta = parser_state_tos->n_comment_delta;
  259.         cur_col = count_spaces(cur_col, com_st);
  260.         ++parser_state_tos->com_lines;    /* count lines with comments */
  261.         }
  262.       }
  263.     if (parser_state_tos->use_ff)
  264.       {
  265.         putc('\014', output);
  266.         parser_state_tos->use_ff = false;
  267.       }
  268.     else
  269.         putc('\n', output);
  270. inhibit_newline:
  271.     ++parser_state_tos->out_lines;
  272.     if (parser_state_tos->just_saw_decl == 1 && blanklines_after_declarations) {
  273.         prefix_blankline_requested = 1;
  274.         parser_state_tos->just_saw_decl = 0;
  275.     }
  276.     else
  277.         prefix_blankline_requested = postfix_blankline_requested;
  278.     postfix_blankline_requested = 0;
  279.     }
  280.     parser_state_tos->decl_on_line = parser_state_tos->in_decl;    /* if we are in the middle of a
  281.                      * declaration, remember that fact for
  282.                      * proper comment indentation */
  283.     parser_state_tos->ind_stmt = parser_state_tos->in_stmt & ~parser_state_tos->in_decl;    /* next line should be
  284.                          * indented if we have not
  285.                          * completed this stmt and if
  286.                          * we are not in the middle of
  287.                          * a declaration */
  288.     parser_state_tos->dumped_decl_indent = 0;
  289.     *(e_lab = s_lab) = '\0';    /* reset buffers */
  290.     *(e_code = s_code) = '\0';
  291.     *(e_com = s_com) = '\0';
  292.     parser_state_tos->ind_level = parser_state_tos->i_l_follow;
  293.     parser_state_tos->paren_level = parser_state_tos->p_l_follow;
  294.     paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
  295.     not_first_line = 1;
  296.     return;
  297. }
  298.  
  299. /* Figure out where we should put the code in codebuf.
  300.    Return the column number in spaces.  */
  301. int
  302. compute_code_target()
  303. {
  304.     register    target_col = parser_state_tos->ind_level + 1;
  305.  
  306.     if (parser_state_tos->paren_level)
  307.     if (!lineup_to_parens)
  308.         target_col += continuation_indent * parser_state_tos->paren_level;
  309.     else {
  310.         register    w;
  311.         register    t = paren_target;
  312.  
  313.         if ((w = count_spaces(t, s_code) - max_col) > 0
  314.             && count_spaces(target_col, s_code) <= max_col) {
  315.         t -= w + 1;
  316.         if (t > target_col)
  317.             target_col = t;
  318.         }
  319.         else
  320.         target_col = t;
  321.     }
  322.     else if (parser_state_tos->ind_stmt)
  323.     target_col += continuation_indent;
  324.     return target_col;
  325. }
  326.  
  327. int
  328. compute_label_target()
  329. {
  330.     return
  331.     parser_state_tos->pcase ? case_ind + 1
  332.     : *s_lab == '#' ? 1
  333.     : parser_state_tos->ind_level - label_offset + 1;
  334. }
  335.  
  336. /* Allocate space for FILENAME, read in the file, and set in_prog and 
  337.    in_prog_pos to point to the buffer.  If any errors occur, report an 
  338.    error message and abort.  */
  339. void
  340. read_file(filename)
  341.      char *filename;
  342. {
  343.   /* File descriptor for the input file */
  344.   int in_fd;
  345.  
  346.   /* File status for the input file */
  347.   struct stat in_stat;
  348.  
  349.   /* buffer used for error messages */
  350.   char *errbuf;
  351.  
  352.   errbuf = (char *)xmalloc (strlen (filename) + 80);
  353.   sprintf(errbuf,"indent: %s",filename);
  354.  
  355.   in_fd = open(filename,O_RDONLY,0777);
  356.   if (in_fd < 0)
  357.     {
  358.       perror(errbuf);
  359.       exit(1);
  360.     }
  361.  
  362.   if (fstat(in_fd,&in_stat) < 0)
  363.     {
  364.       perror(errbuf);
  365.       exit(1);
  366.     }
  367.   in_prog_size = in_stat.st_size;
  368.   in_prog = xmalloc(in_prog_size + 3); /* 3 for ' ','\n','\0' */
  369.  
  370.   if (read(in_fd,in_prog,in_prog_size) < 0)
  371.     {
  372.       perror(errbuf);
  373.       exit(1);
  374.     }
  375.  
  376.   if (close(in_fd) < 0)
  377.     {
  378.       perror(errbuf);
  379.       exit(1);
  380.     }
  381.  
  382.   in_prog[in_prog_size] = ' ';
  383.   in_prog[in_prog_size+1] = '\n';
  384.   in_prog[in_prog_size+2] = 0;
  385.   in_prog_pos = in_prog;
  386.  
  387.   free (errbuf);
  388. }
  389.  
  390. /* Like read_file but read from stdin.  */
  391. void
  392. read_stdin()
  393. {
  394.   unsigned int alloc_size = 10000;
  395.   int ch;
  396.  
  397.   in_prog_pos = in_prog = xmalloc(alloc_size);
  398.   in_prog_size = 0;
  399.   do
  400.     {
  401.       /* Copy up until 3 bytes before the end of the buffer,
  402.      (the 3 is for ' \n\0')...  */
  403.       for (; in_prog_size < alloc_size - 3; in_prog_size++)
  404.     {
  405.       ch = getc(stdin);
  406.       if (ch == EOF)
  407.           break;
  408.       in_prog[in_prog_size] = ch;
  409.     }
  410.       /* ...and if that's not enough allocate more.  */
  411.       if (ch != EOF) {
  412.     alloc_size *= 2;
  413.     in_prog = xrealloc(in_prog,alloc_size);
  414.       }
  415.     }
  416.   while (ch != EOF);
  417.   
  418.   in_prog[in_prog_size] = ' ';
  419.   in_prog[in_prog_size+1] = '\n';
  420.   in_prog[in_prog_size+2] = 0;
  421.   in_prog_pos = in_prog;  
  422. }
  423.  
  424. /* Advance buf_ptr so that it points to the next line of input.  Skip 
  425.    over indent errors (comments beginning with *INDENT**), ignoring
  426.    them.  Process INDENT ON and INDENT OFF. (Note: the name of this
  427.    function is a historical artifact from before the time that indent
  428.    kept the whole source file in memory). */
  429.  
  430. fill_buffer()
  431. {
  432.   /* Point various places in the buffer.  */
  433.   char *p;
  434.  
  435.   /* Have we found INDENT ON or INDENT OFF ? */
  436.   enum {None,Indent_on,Indent_off} com;
  437.   
  438.   if (bp_save != 0)
  439.     {        /* there is a partly filled input buffer left */
  440.     buf_ptr = bp_save;    /* dont read anything, just switch buffers */
  441.     buf_end = be_save;
  442.     bp_save = be_save = 0;
  443.     if (buf_ptr < buf_end)
  444.         return;        /* only return if there is really something in
  445.                  * this buffer */
  446.     }
  447.  
  448.   fill_it:
  449.  
  450.   cur_line = in_prog_pos;
  451.   buf_ptr = in_prog_pos;
  452.   for (p = buf_ptr; *p && *p++ != '\n';)
  453.     ;
  454.   
  455.   buf_end = p;
  456.   if (!*p)
  457.     had_eof = true;
  458.  
  459.   p = buf_ptr;
  460.   in_prog_pos = buf_end;
  461.   
  462.   while (*p == ' ' || *p == '\t')
  463.     p++;
  464.   if (*p == '/' && p[1] == '*')
  465.     {
  466.       p += 2;
  467.       if (p[1] == 'I' && strncmp(p,"*INDENT**",9) == 0)
  468.     goto fill_it;
  469.       while (*p == ' ' || *p == '\t')
  470.     p++;
  471.       com = None;
  472.       if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
  473.             && p[4] == 'N' && p[5] == 'T') {
  474.             p += 6;
  475.             while (*p == ' ' || *p == '\t')
  476.             p++;
  477.             if (*p == '*')
  478.             com = Indent_on;
  479.             else if (*p == 'O')
  480.             if (*++p == 'N')
  481.                 p++, com = Indent_on;
  482.             else if (*p == 'F' && *++p == 'F')
  483.                 p++, com = Indent_off;
  484.             while (*p == ' ' || *p == '\t')
  485.             p++;
  486.             if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
  487.             if (s_com != e_com || s_lab != e_lab || s_code != e_code)
  488.                 dump_line();
  489.             if (!(inhibit_formatting = (int)com - 1)) {
  490.                 n_real_blanklines = 0;
  491.                 postfix_blankline_requested = 0;
  492.                 prefix_blankline_requested = 0;
  493.                 suppress_blanklines = 1;
  494.             }
  495.             }
  496.           }
  497.     }
  498.   if (inhibit_formatting)
  499.     {
  500.       p = buf_ptr;
  501.       do
  502.     putc(*p,output);
  503.       while (*p++ != '\n');
  504.     }
  505.       
  506. }
  507.   
  508.       
  509.   
  510. /*
  511.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  512.  * 
  513.  * All rights reserved
  514.  * 
  515.  * 
  516.  * NAME: pad_output
  517.  * 
  518.  * FUNCTION: Writes tabs and spaces to move the current column up to the desired
  519.  * position.
  520.  * 
  521.  * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
  522.  * 
  523.  * PARAMETERS: current        integer        The current column target
  524.  * nteger        The desired column
  525.  * 
  526.  * RETURNS: Integer value of the new column.  (If current >= target, no action is
  527.  * taken, and current is returned.
  528.  * 
  529.  * GLOBALS: None
  530.  * 
  531.  * CALLS: write (sys)
  532.  * 
  533.  * CALLED BY: dump_line
  534.  * 
  535.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  536.  * 
  537.  */
  538. pad_output(current, target)    /* writes tabs and blanks (if necessary) to
  539.                  * get the current output position up to the
  540.                  * target column */
  541.     int         current;    /* the current column value */
  542.     int         target;        /* position we want it at */
  543. {
  544.     register int curr;        /* internal column pointer */
  545.     register int tcur;
  546.  
  547.     if (troff)
  548.     fprintf(output, "\\h'|%dp'", (target - 1) * 7);
  549.     else {
  550.     if (current >= target)
  551.         return (current);    /* line is already long enough */
  552.     curr = current;
  553.     while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
  554.         putc('\t', output);
  555.         curr = tcur;
  556.     }
  557.     while (curr++ < target)
  558.         putc(' ', output);    /* pad with final blanks */
  559.     }
  560.     return (target);
  561. }
  562.  
  563. /*
  564.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  565.  * 
  566.  * All rights reserved
  567.  * 
  568.  * 
  569.  * NAME: count_spaces
  570.  * 
  571.  * FUNCTION: Find out where printing of a given string will leave the current
  572.  * character position on output.
  573.  * 
  574.  * ALGORITHM: Run thru input string and add appropriate values to current
  575.  * position.
  576.  * 
  577.  * RETURNS: Integer value of position after printing "buffer" starting in column
  578.  * "current".
  579.  * 
  580.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  581.  * 
  582.  */
  583. int
  584. count_spaces(current, buffer)
  585. /*
  586.  * this routine figures out where the character position will be after
  587.  * printing the text in buffer starting at column "current"
  588.  */
  589.     int         current;
  590.     char       *buffer;
  591. {
  592.     register char *buf;        /* used to look thru buffer */
  593.     register int cur;        /* current character counter */
  594.  
  595.     cur = current;
  596.  
  597.     for (buf = buffer; *buf != '\0'; ++buf) {
  598.     switch (*buf) {
  599.  
  600.     case '\n':
  601.     case 014:        /* form feed */
  602.         cur = 1;
  603.         break;
  604.  
  605.     case '\t':
  606.         cur = ((cur - 1) & tabmask) + tabsize + 1;
  607.         break;
  608.  
  609.     case 010:        /* backspace */
  610.         --cur;
  611.         break;
  612.  
  613.     default:
  614.         ++cur;
  615.         break;
  616.     }            /* end of switch */
  617.     }                /* end of for loop */
  618.     return (cur);
  619. }
  620.  
  621. /* Nonzero if we have found an error (not a warning).  */
  622. int    found_err;
  623.  
  624. /* Signal an error.  LEVEL is nonzero if it is an error (as opposed to 
  625.    a warning.  MSG is a printf-style format string.  Additional 
  626.    arguments are additional arguments for printf.  */
  627. /* VARARGS2 */
  628. diag(level, msg, a, b)
  629.      char *msg;
  630. {
  631.     if (level)
  632.     found_err = 1;
  633.     if (output == stdout) {
  634.     fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  635.     fprintf(stdout, msg, a, b);
  636.     fprintf(stdout, " */\n");
  637.     }
  638.     else {
  639.     fprintf(stderr, "%s: %d: ", in_name, line_no);
  640.     fprintf(stderr, msg, a, b);
  641.     fprintf(stderr, "\n");
  642.     }
  643. }
  644.  
  645. writefdef(f, nm)
  646.     register struct fstate *f;
  647. {
  648.     fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
  649.         nm, f->font, nm, f->size);
  650. }
  651.  
  652. /* Write characters starting at S to change the font from OF to NF.  Return
  653.    a pointer to the character after the last character written.
  654.    For troff mode only.  */
  655. char *
  656. chfont(of, nf, s)
  657.     register struct fstate *of,
  658.                *nf;
  659.     char       *s;
  660. {
  661.     if (of->font[0] != nf->font[0]
  662.         || of->font[1] != nf->font[1]) {
  663.     *s++ = '\\';
  664.     *s++ = 'f';
  665.     if (nf->font[1]) {
  666.         *s++ = '(';
  667.         *s++ = nf->font[0];
  668.         *s++ = nf->font[1];
  669.     }
  670.     else
  671.         *s++ = nf->font[0];
  672.     }
  673.     if (nf->size != of->size) {
  674.     *s++ = '\\';
  675.     *s++ = 's';
  676.     if (nf->size < of->size) {
  677.         *s++ = '-';
  678.         *s++ = '0' + of->size - nf->size;
  679.     }
  680.     else {
  681.         *s++ = '+';
  682.         *s++ = '0' + nf->size - of->size;
  683.     }
  684.     }
  685.     return s;
  686. }
  687.  
  688.  
  689. parsefont(f, s0)
  690.     register struct fstate *f;
  691.     char       *s0;
  692. {
  693.     register char *s = s0;
  694.     int         sizedelta = 0;
  695.     int i;
  696.     
  697.     f->size = 0;
  698.     f->allcaps = 1;
  699.     for (i = 0; i < 4; i++)
  700.       f->font[i] = 0;
  701.     
  702.     while (*s) {
  703.     if (isdigit(*s))
  704.         f->size = f->size * 10 + *s - '0';
  705.     else if (isupper(*s))
  706.         if (f->font[0])
  707.         f->font[1] = *s;
  708.         else
  709.         f->font[0] = *s;
  710.     else if (*s == 'c')
  711.         f->allcaps = 1;
  712.     else if (*s == '+')
  713.         sizedelta++;
  714.     else if (*s == '-')
  715.         sizedelta--;
  716.     else {
  717.         fprintf(stderr, "indent: bad font specification: %s\n", s0);
  718.         exit(1);
  719.     }
  720.     s++;
  721.     }
  722.     if (f->font[0] == 0)
  723.     f->font[0] = 'R';
  724.     if (bodyf.size == 0)
  725.     bodyf.size = 11;
  726.     if (f->size == 0)
  727.     f->size = bodyf.size + sizedelta;
  728.     else if (sizedelta > 0)
  729.     f->size += bodyf.size;
  730.     else
  731.     f->size = bodyf.size - f->size;
  732. }
  733.